#pragma once
#include <iostream>
#include <algorithm>
using namespace std;

template <class T>
class interval
{
private:
	T lower;
	T upper;
public:

	interval()
	{
		lower = upper = 0;
	}

	interval(T mean, double procent)
	{
		lower = (T)(mean - mean * (procent / 100.0));
		upper = (T)(mean + mean * (procent / 100.0));
	}

	friend interval<T> operator+(const interval<T> &lop, const interval<T> &rop)
	{
		interval <T> m;
		m.upper = lop.upper + rop.upper;
		m.lower = lop.lower + rop.lower;
		return m;
	}

	friend interval<T> operator*(const interval<T> &lop, const interval<T> &rop)
	{
		interval <T> m;
		auto result = minmax({ (lop.lower * rop.lower), (lop.lower * rop.upper), (lop.upper*rop.lower), (lop.upper*rop.upper) });
		
		m.lower = result.first;
		m.upper = result.second;
	
		return m;
	}

	friend interval<T> operator-(const interval<T> &lop, const interval<T> &rop)
	{
		interval <T> m;
		m.upper = lop.upper - rop.upper;
		m.lower = lop.lower - rop.lower;
		return m;
	}

	friend interval<T> operator/(const interval<T> &lop, const interval<T> &rop)
	{
		interval <T> m;
		auto result = minmax({ (lop.lower / rop.lower), (lop.lower / rop.upper), (lop.upper / rop.lower), (lop.upper / rop.upper) });
		
		m.lower = result.first;
		m.upper = result.second;

		return m;
	}

	T mean()
	{
		return ((upper + lower) / 2);
	}

	double absolute_error()
	{
		return ((double)upper - (double)lower) / 2;
	}

	double percentage_error()
	{
		return (100 * ((double)upper - (double)lower) / (double)mean());
	}

	void print_absolute()
	{
		cout << "mean: " << mean() << ", absolute error: " << absolute_error() << endl;
	}

	void print_percentage()
	{
		cout << "mean: " << mean() << ", percantage error: " << percentage_error() << endl;
	}

	friend ostream& operator<<(ostream &out, const interval<T> &rop)
	{
		out << "[" << rop.lower << "," << rop.upper << "]";
		return out;
	}

	//T GetUpper() { return this->upper; }
	//T GetLower(){ return this->lower; }
		

	~interval()
	{
	}
};

